/*
 * @Author: wangjun haodreams@163.com
 * @Date: 2024-05-19 14:17:06
 * @LastEditors: wangjun haodreams@163.com
 * @LastEditTime: 2024-05-19 17:38:40
 * @FilePath: \libs\fsx\fsx.go
 * @Description: http 协议的文件下载上传
 */
package fsx

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"

	"gitee.com/haodreams/libs/easy"
)

type FS struct {
	root       string
	match      string
	rootUpload string
	mathUpload string
}

// fx := fsx.New("/files/", ".")
// fx.SetUploadPath("/upload/", ".")
// route.GET(fx.GinPattern(), func(c *gin.Context) {
// 	fx.ServeHTTP(c.Writer, c.Request)
// })
// route.GET(fx.GinUploadPattern(), func(c *gin.Context) {
// 	fx.Upload(c.Writer, c.Request)
// })
// route.POST(fx.GinUploadPattern(), func(c *gin.Context) {
// 	fx.Upload(c.Writer, c.Request)
// })

func New(match, root string) *FS {
	fs := new(FS)
	if !strings.HasSuffix(root, "/") {
		root += "/"
	}
	fs.root = root
	fs.match = match
	return fs
}

func (m *FS) Pattern() string {
	return m.match
}
func (m *FS) GinPattern() string {
	return m.match + "*path"
}

func (m *FS) GinUploadPattern() string {
	return m.mathUpload + "*path"
}

func (m *FS) SetUploadPath(match, root string) {
	if !strings.HasSuffix(root, "/") {
		root += "/"
	}
	m.rootUpload = root
	m.mathUpload = match
}

func (m *FS) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	filePath := r.URL.Path
	filePath = filePath[len(m.match):]
	filePath = path.Clean(filePath)
	filePath = m.root + filePath
	fi, err := os.Stat(filePath)
	if err != nil {
		http.NotFound(w, r)
		return
	}
	if fi.IsDir() {
		m.List(w, r, filePath)
		return
	}
	http.ServeFile(w, r, filePath)
}

func (m *FS) err(w http.ResponseWriter, data string, codes ...int) {
	code := 412
	if len(codes) > 0 {
		code = codes[0]
	}
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	_, err := w.Write([]byte(fmt.Sprintf(`{"code":%d,"msg":"%s"}`, code, data)))
	if err != nil {
		log.Println(err.Error())
		return
	}
	w.Write([]byte(`{"code":200,"msg":"OK"}`))
}

func (m *FS) msg(w http.ResponseWriter, data string) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	_, err := w.Write([]byte(`{"code":200,"msg":"` + data + `"}`))
	if err != nil {
		log.Println(err.Error())
		return
	}
}

func (m *FS) Upload(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		html := `<!DOCTYPE html>
		<html> 
		<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>上传文件</title></head>
		<body><form method="post" enctype="multipart/form-data">
		<input type="file" name="file" value="" /> 	<input type="submit" name="submit" />
		</form></body></html>`

		w.Header().Add("Content-Type", "text/html")
		w.WriteHeader(200)
		w.Write([]byte(html))
		return
	}
	r.ParseForm()
	filePath := r.URL.Path
	filePath = filePath[len(m.match):]
	filePath = path.Clean(filePath)
	filePath = m.root + filePath

	easy.MkdirAll(filePath)
	if !strings.HasSuffix(filePath, "/") {
		filePath += "/"
	}
	_, header, err := r.FormFile("file")
	if err != nil {
		w.Write([]byte(err.Error()))
		return
	}
	dst := header.Filename
	fileName := filepath.Base(dst)
	f, err := header.Open()
	if err != nil {
		m.err(w, err.Error())
		return
	}
	defer f.Close()

	lf, err := os.Create(filePath + fileName)
	if err != nil {
		m.err(w, err.Error())
		return
	}

	defer lf.Close()

	size, _ := io.Copy(lf, f)
	msg := easy.BeautifySize(size)
	m.msg(w, msg)
}

func (m *FS) List(w http.ResponseWriter, r *http.Request, path string) {
	fis, err := os.ReadDir(path)
	if err != nil {
		http.NotFound(w, r)
		return
	}

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.Write([]byte(`<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>文件浏览</title></head><body>`))
	fmt.Fprintf(w, "<table  border=\"0\">\n")
	w.Write([]byte("<tr><td>文件名称</td><td>文件大小</td><td>修改时间</td></tr>"))
	for _, f := range fis {
		name := f.Name()
		size := "-"
		fi, err := f.Info()
		if err != nil {
			continue
		}
		if f.IsDir() {
			name += "/"
		} else {
			size = easy.BeautifySize(fi.Size())
		}
		url := url.URL{Path: name}
		fmt.Fprintf(w, "<tr><td><a href=\"%s\">%s</a></td><td>%s</td><td>%s</td></tr>\n", url.String(), name, size, easy.FormatTime(fi.ModTime().Unix()))
	}
	fmt.Fprintf(w, "</table>\n")
	w.Write([]byte("</body></html>"))
}
